package net.csdn.business.mirror.scheduled.handler;

import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.utils.RedisLockUtils;
import net.csdn.business.common.utils.SurvivalClamProcessor;
import net.csdn.business.mirror.entity.bean.ScheduleTask;
import net.csdn.business.mirror.enums.ScheduleTaskEnum;
import net.csdn.business.mirror.service.ScheduleTaskImplement;
import net.csdn.business.mirror.SpringBeanUtil;
import net.csdn.business.mirror.utils.TimeUtil;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.Duration;
import java.util.Objects;

/**
 * 动态任务3
 * 实际执行任务实现类
 */
@Slf4j
public class ReleaseTask implements Runnable {

    private ScheduleTask scheduleTask;

    private static final String LOCK_KEY_STR = "schedule_tasks:";

    public ReleaseTask(ScheduleTask scheduleTask) {
        this.scheduleTask = scheduleTask;
    }

    @Override
    public void run() {
        RedisLockUtils redisLockUtils = SpringBeanUtil.getBean(RedisLockUtils.class);
        //对定时任务增加分布式锁，并且可以自动延长锁时长
        StringBuilder key=new StringBuilder(LOCK_KEY_STR);
        String name=scheduleTask.getName();
        key.append(name);
        ScheduleTaskEnum.Name nameEnum = ScheduleTaskEnum.Name.parse(scheduleTask.getName());
        if (Objects.isNull(nameEnum)) {
            return;
        }
        //增加分布式锁，防止多实例时候并发执行，锁是30秒，守护线程在三分之二过期时间之前进行续期
        String identifier=redisLockUtils.lock(key.toString(),30);
        if(identifier!=null){
            log.info("---------schedule task:{} is started-------",name);
            //定义锁的延时守护线程
            SurvivalClamProcessor survivalClamProcessor = new SurvivalClamProcessor(redisLockUtils,key.toString(), 30);;
            //定义守护线程
            Thread survivalThread = new Thread(survivalClamProcessor);
            survivalThread.setDaemon(Boolean.TRUE);
            survivalThread.start();
            try{
                ScheduleTaskImplement scheduleTaskImplement = SpringBeanUtil.getBean(nameEnum.getScheduleTaskImplementService());
                scheduleTaskImplement.exec(scheduleTask);
                log.info("---------schedule task:{} is finished-------",name);
            }catch (Exception e){
                log.error("---------schedule task:{}  error:{} ----",name,e.getMessage());
            }finally {
                redisLockUtils.unlock(key.toString(),identifier);
            }
        }else{
            log.info("---------schedule task:{} is runing in other,this is cancled-------",name);
        }
    }
}
